using System;
using System.Collections;
using Iesi.Collections;

namespace Sedna.Util
{
    public class TransientSet : ISet
    {
        private ArrayList persistedData = new ArrayList();
        private ArrayList notPersistedData = new ArrayList();
        private ArrayList transientData;
        
        [Obsolete]
        private IComparer sortComparer = EqualsComparer.GetInstance();
        
        #region Constructors
        
        public TransientSet() 
            //: this(EqualsComparer.GetInstance())
        {}
        /*
        [Obsolete]
        public TransientSet(IComparer sortComparer)
        {
            this.sortComparer = sortComparer;
            transientData = new ArrayList();
        }
        */
        public TransientSet(ICollection collection)
            //: this(collection, EqualsComparer.GetInstance())
        {}
        /*
        [Obsolete]
        public TransientSet(ICollection collection, IComparer sortComparer)            
        {
            this.sortComparer = sortComparer;
            transientData = new ArrayList();
            AddAll(collection);
        }
        */
        #endregion

        #region Properties

        /// <summary>
        /// Not sorted persisted elements
        /// </summary>
        public ICollection PersistentData
        {
            get { return persistedData; }
        }
        
        /// <summary>
        /// Not sorted not persisted elements
        /// </summary>
        public ICollection NotPersistedData
        {
            get { return notPersistedData;}
        }
        
        /// <summary>
        /// Sorted elements of result of union persisted and not persisted elements
        /// </summary>
        [Obsolete]
        public IList SortedData
        {
            get
            {
                //transientData.Sort(sortComparer);
                return transientData;
            }
        }
        
        #endregion

        #region ISet members

        /// <summary>
        /// Priority is given to elements of this set
        /// </summary>
        public ISet Union(ISet a)
        {
            ArrayList result = new ArrayList(a);
            foreach (object o in this)
            {
                int elementIndex = result.IndexOf(o);
                if (result.IndexOf(o) >= 0)
                {
                    result[elementIndex] = o;
                }
                else
                {
                    //TODO: Unsorted insert. Should be fixed
                    result.Add(o);
                }
            }            
            return new TransientSet(result);
        }

        /// <summary>
        /// Priority is given to elements of this set
        /// </summary>
        public ISet Intersect(ISet a)
        {
            ISet result = new TransientSet();// new TransientSet(sortComparer);
            foreach (object o in a)
            {
                if (Contains(o))
                {
                    result.Add(o);
                }
            }
            return result;
        }

        public ISet Minus(ISet a)
        {
            ISet result = (ISet)Clone();
            result.RemoveAll(a);
            return result;
        }

        public ISet ExclusiveOr(ISet a)
        {
            return Union(a).Minus(Intersect(a));
        }

        public bool Contains(object o)
        {
            if (Utility.IsPersisted(o))
            {
                return persistedData.Contains(o);
            }

            return false;
        }

        public bool ContainsAll(ICollection c)
        {
            foreach (object o in c)
            {
                if (!Contains(o))
                {
                    return false;
                }
            }
            
            return true;
        }

        public bool Add(object o)
        {
            if (!Contains(o))
            {
                if (Utility.IsPersisted(o))
                {
                    persistedData.Add(o);
                }
                else if (Utility.IsPersistent(o))
                {
                    notPersistedData.Add(o);
                }
                                
                transientData.Add(o);

                return true;
            }

            return false;
        }

        public bool AddAll(ICollection c)
        {
            bool allAdded = true;
            foreach (object o in c)
            {
                allAdded = allAdded && Add(o);
            }
            return allAdded;
        }

        public bool Remove(object o)
        {
            if (Contains(o))
            {
                if (Utility.IsPersisted(o))
                {
                    persistedData.Remove(o);
                }
                else if (Utility.IsPersistent(o))
                {
                    notPersistedData.Remove(o);
                }

                /* All elements must be enumerated because sort property and 
                    equals method could be independent from each other */
                for (int i = 0; i < transientData.Count; i++)
                {
                    if (o.Equals(transientData[i]))
                    {
                        transientData.RemoveAt(i);
                        break;
                    }
                }

                return true;
            }

            return false;
        }

        public bool RemoveAll(ICollection c)
        {
            bool allRemoved = true;
            foreach (object o in c)
            {
                allRemoved = allRemoved && Remove(o);
            }
            return allRemoved;
        }

        public bool RetainAll(ICollection c)
        {
            ISet removedSet = new TransientSet(this);
            
            bool retainedAll = removedSet.RemoveAll(c);
            RemoveAll(removedSet);

            return retainedAll;
        }

        public void Clear()
        {
            persistedData.Clear();
            notPersistedData.Clear();
            transientData.Clear();
        }

        public bool IsEmpty
        {
            get { return (Count == 0);}
        }

        public void CopyTo(Array array, int index)
        {
            transientData.Sort(sortComparer);
            transientData.CopyTo(array, index);
        }

        public int Count
        {
            get { return transientData.Count;}
        }

        public object SyncRoot
        {
            get { return transientData.SyncRoot;}
        }

        public bool IsSynchronized
        {
            get { return transientData.IsSynchronized;}
        }

        public IEnumerator GetEnumerator()
        {
            //transientData.Sort(sortComparer);
            return transientData.GetEnumerator();
        }

        public object Clone()
        {
            return new TransientSet(transientData);//new TransientSet(transientData, sortComparer);
        }

        #endregion        
        
        private class EqualsComparer : IComparer
        {
            private static EqualsComparer INSTANCE = new EqualsComparer();

            private EqualsComparer()
            { }

            public static EqualsComparer GetInstance()
            {
                return INSTANCE;
            }

            /// <summary>
            /// Represents non stable sorting.
            /// Comparing firstly by hash code and then by equals. 
            /// If equals returns false, negative value will be returned.
            /// </summary>
            public int Compare(object x, object y)
            {
                if (x.Equals(y))
                {
                    return 0;
                }

                return (x.GetHashCode() <= y.GetHashCode() ? -1 : 1);
            }            
        }
    }
}
